#include "Sock.hpp"
#include<sys/epoll.h>

#define BACK_LOG 5
#define SIZE 256
#define MAX_NUM 64

class EpollServer{
private:
    int _listen_sock;
    int _port;
    int _epfd;

public:
    EpollServer(int port)
    :_port(port) {}

    void InitEpollServer()
    {
    _listen_sock = Sock::Socket();
    Sock::Bind(_listen_sock, _port);
    Sock::Listen(_listen_sock);

    //创建epoll模型
    _epfd = epoll_create(SIZE);
    if(_epfd < 0)
    {
        std::cerr << "epoll_create error" << std::endl;
        exit(5);
    }
    }

    ~EpollServer()
    {
        if(_listen_sock >= 0)
        {
            close(_listen_sock);
        }

        if(_epfd >= 0) close(_epfd);
    }

    void Run()
    {
        AddEvent(_listen_sock, EPOLLIN);//将监听套接字添加到epoll中，并关心其读事件
        for(;;){
            struct epoll_event revs[MAX_NUM];
            int num = epoll_wait(_epfd, revs, MAX_NUM, -1);
            if(num < 0)
            {
                std::cerr << "epoll_wait error " << std::endl;
                continue;
            }
            else if(num == 0)
            {
                std::cout << "timeout..." << std::endl;
                continue; 
            }
            else
            {
                //正常的事件处理,
                HandlerEvent(revs, num);
            }
        }
    }

    void HandlerEvent(struct epoll_event revs[], int num)
    {
        for(int i = 0; i < num; i++)
        {
            int fd = revs[i].data.fd;//就绪的文件描述符
            if( fd == _listen_sock&&revs[i].events&EPOLLIN)
            {
                //连接事件就绪
                struct sockaddr_in peer;
                memset(&peer, 0, sizeof(peer));
                socklen_t len = sizeof(peer);
                int sock = accept(_listen_sock, (struct sockaddr*)&peer, &len);
                if(sock < 0){
                    // 获取新连接
                    std::cerr << "accept error" << std::endl;
                    continue;
                }

                std::string peer_ip = inet_ntoa(peer.sin_addr);
                int peer_port = ntohs(peer.sin_port);
                std::cout << "get a new link ["<< peer_ip << " : "<< peer_port << "]" << std::endl;
                AddEvent(sock, EPOLLIN);//将获取到的套接字添加到epoll模型中,并关心其读事件

            }
            else if(revs[i].events&EPOLLIN)
            {
                //读事件就绪
                char buffer[64];
                ssize_t size = recv(fd, buffer, sizeof(buffer - 1), 0);
                if(size > 0)
                {
                    //读取成功
                    buffer[size] = '\0';
                    std::cout << "echo#" << buffer << std::endl;
                }
                else if(size == 0)
                {
                    //关闭对端连接
                    std::cout << "client quit" << std::endl;
                    close(fd);
                    DelEvent(fd);//将文件描述符从epoll中删除
                }
                else{
                    std::cerr << "recv error" << std::endl;
                    close(fd);
                    DelEvent(fd);
                }
            }
        }
    }


private:
    void AddEvent(int sock, uint32_t event)
    {
        struct epoll_event ev;
        ev.events = event;
        ev.data.fd = sock;

        epoll_ctl(_epfd, EPOLL_CTL_ADD, sock, &ev);
    }

    void DelEvent(int sock)
    {
        epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
    }

};